package com.ruoyi.utils;

import cn.hutool.core.date.DateException;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.annotation.BeanFieldType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 实体类属性类型校验工具
 *
 * @author: Gao Tianle
 * @date: 2023-11-27 11:35
 **/
public class BeanFieldTypeVerUtil {

    /**
     * 判断字段类型
     * (目前只录入常用字段类型：String,Integer,int,
     * Double,double,Float,float,Long,long,Date)
     *
     * @param o
     */
    public static void isFieldType(Object o) {
        //通过反射获取字段名
        List<String> tableFieldName = getBeanFieldName(o);
        for (String fieldName : tableFieldName) {
            //通过反射获取ApiModelProperty注解的参数
            BeanFieldType beanFieldType = getTableFieldValue(o, fieldName);
            //为空不进行验证
            if (StringUtils.isNull(beanFieldType)) {
                continue;
            }
            // 构造get方法名
            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase()
                    + fieldName.substring(1);
            // 获取get方法对象
            Method getMethod = null;
            try {
                getMethod = o.getClass().getMethod(getMethodName);
                // 调用get方法获取值
                String value = (String) getMethod.invoke(o);
                if (StringUtils.isNotEmpty(value)) {
                    isType(beanFieldType, value);
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取实体所有字段
     *
     * @param o
     * @return
     */
    private static List<String> getBeanFieldName(Object o) {
        List<String> stringList = new ArrayList<>();
        Field[] fields = o.getClass().getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            stringList.add(fieldName);
        }
        return stringList;
    }

    /**
     * 获取字段注解
     *
     * @param main
     * @return
     */
    private static BeanFieldType getTableFieldValue(Object main, String label) {
        BeanFieldType beanFieldType = null;
        try {
            Field field = main.getClass().getDeclaredField(label);
            beanFieldType = field.getAnnotation(BeanFieldType.class);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return beanFieldType;
    }

    /**
     * 字段类型判断
     *
     * @param beanFieldType 字段上的类型注解
     * @param value         字段值
     */
    private static void isType(BeanFieldType beanFieldType, String value) {
        BeanFieldType.Type type = beanFieldType.type();
        String msg = beanFieldType.name() + "传值错误";
        switch (type.value()) {
            case 0:
                break;
            case 1:
                try {
                    Integer.parseInt(value);
                } catch (NumberFormatException e) {
                    throw new ServiceException(msg);
                }
                break;
            case 2:
                try {
                    Double.parseDouble(value);
                } catch (NumberFormatException e) {
                    throw new ServiceException(msg);
                }
                break;
            case 3:
                try {
                    Float.parseFloat(value);
                } catch (NumberFormatException e) {
                    throw new ServiceException(msg);
                }
                break;
            case 4:
                try {
                    Long.parseLong(value);
                } catch (NumberFormatException e) {
                    throw new ServiceException(msg);
                }
                break;
            case 5:
                try {
                    DateUtil.parse(value);
                } catch (DateException e) {
                    throw new ServiceException(msg);
                }
                break;
        }
    }
}
